#include <gtest/gtest.h>

#include "optional"

TEST(OptionalTest, use){

	const char * origin_cstr = "100";
	const std::string expect_str{origin_cstr};

	std::optional<std::string> op_s{origin_cstr};
	// operator bool()
	ASSERT_TRUE(op_s);
	// T & value();
	ASSERT_EQ(expect_str, op_s.value());
	// operato*  -> T &
	ASSERT_EQ(expect_str, *op_s);

	// operator * -> T&&
	auto && rv_ref_op_s = *op_s;
	ASSERT_EQ(expect_str, rv_ref_op_s);

	// operator-> return T *
	ASSERT_EQ(expect_str.size(), op_s->size());
	
	//reset
	op_s.reset();
	ASSERT_FALSE(op_s);

	//value_or
	const std::string default_str = "0";
	ASSERT_EQ(default_str, op_s.value_or(std::move(std::string("0"))));

	// inplace construct the optional object
	op_s.emplace(origin_cstr);
}

TEST(OptionalTest, reference_wrapper){
	// next code compile error: cannot initialization the T & in ctor with no-value
	// std::optional<int &> op_ref = nullopt; 

	const char * origin_cstr = "100";
	const std::string expect_str{origin_cstr};
	const std::string & ref_str = expect_str;

	using opt_string_ref_type = std::optional<std::reference_wrapper<const std::string>>;

	{//nullopt for ref_type of optional
		opt_string_ref_type op_ref_nullopt = std::nullopt;
		ASSERT_FALSE(op_ref_nullopt);
	}

	{// T& for ref_type of optional
		opt_string_ref_type op_ref {ref_str};
		ASSERT_TRUE(op_ref);
	}

	{
		std::unique_ptr<std::string> pstr(new std::string(origin_cstr));
		opt_string_ref_type op_ref {*pstr};
		ASSERT_TRUE(op_ref);
	}
}
